# Wei Jiang

from twisted.internet.protocol import Factory
from twisted.internet.protocol import Protocol
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
from twisted.internet.endpoints import TCP4ServerEndpoint

class brokerServerCommand(LineReceiver):
    def __init__(self,factory,users,commands,channels,machineStates,usersWithCorrespondingChannels):
        print "brokerServerCommand init."
        self.dataPortProtocolReference = None
        self.factory = factory
        self.users = users
        self.commands = commands
        self.channels = channels
        self.brokerServerMachineStates = machineStates
        self.usersWithCorrespondingChannels = usersWithCorrespondingChannels
        self.command = None
        self.state = 5
        print "broker state:",self.state,self.brokerServerMachineStates[self.state]

        
    def connectionMade(self):
        #self.state = 0
        #print "Received connection from:"
        self.factory.numCommandProtocols = self.factory.numCommandProtocols + 1
        print "There are currently",self.factory.numCommandProtocols,"open command connections"

        
    def connectionLost(self, reason):
        if self.users.has_key(self.name):
            del self.users[self.name]
            del self.usersWithCorrespondingChannels[self.name]
            self.factory.numCommandProtocols = self.factory.numCommandProtocols - 1
        print "There are currently",self.factory.numCommandProtocols,"open command connections"
    
    def lineReceived(self, line):
        currentCommandCode = int(line.strip())
        print "Command Port: Received:",currentCommandCode
        if currentCommandCode in self.commands:
            if currentCommandCode == 0:
                self.handle_Subscribe()
                #outputLine = "Select channel from "
                #print outputLine,str(self.channels)
                #self.state = 2  
            elif currentCommandCode == 1:
                self.handle_Unsubscribe()
                #if len( self.usersWithCorrespondingChannels[self.name] ) != 0:
                #    outputLine = "Select subscribed channel from "
                #    print outputLine,str(self.usersWithCorrespondingChannels[self.name])," to delete"
                #    self.state = 3
                    
                #else:
                #    print "There are No channels subscribed now."
                #    self.state = 1         
            elif currentCommandCode == 2:
                self.handle_Status()
            elif currentCommandCode == 3:
                self.handle_INIT()
        else:
            print str(currentCommandCode)," is NOT in the commands list."
            outputLine = "Select again commands from "
            for code in self.commands:
                outputLine += self.commands[code] + " "
            print outputLine.strip()
            self.state = 5
            
        '''
        if self.state == 0:
            self.handle_INIT(line)
        elif self.state == 1:
            self.handle_GETCOMMAND(line)
        elif self.state == 2:
            self.handle_GETCHANNEL(line)            
        elif self.state == 3:
            self.handle_DELCHANNEL(line)

        self.sendLine(str(self.state))
        '''

    def handle_Subscribe(self):
        print "handle_Subscribe"
                
    def handle_Unsubscribe(self):
        print "handle_Unsubscribe"
         
    def handle_Status(self):
        print "handle_INIT"
        #logic
        #print "name","channels"
        #for name,channels in self.usersWithCorrespondingChannels.iteritems():
        #    print name,channels
        
        #print "name","protocols"
        #for name,protocol in self.usersWithCorrespondingChannels.iteritems():
        #    print name,protocol
        
        #status changed.
        #self.state = 1


    def handle_DELCHANNEL(self,line):
        code = int( line.strip() )
        if code in self.usersWithCorrespondingChannels[self.name]:
            print "Channel",code,"removed..."
            self.usersWithCorrespondingChannels[self.name].remove( code )
            self.state = 1
            
        else:
            print str(code)," is NOT in the subscribed channel list."
            outputLine = "Select again from "
            print outputLine.strip(),str( self.usersWithCorrespondingChannels[self.name] )
            self.state = 3
            
    
    def handle_GETCHANNEL(self,line):
        code = int(line.strip())
        if code in self.channels:
            print "Channel",code,"selected..."
            self.usersWithCorrespondingChannels[self.name].append( code )
            self.state = 6
        else:
            print str(code)," is NOT in the code list."
            outputLine = "Select again from "
            print outputLine.strip(),str(self.channels)
            self.state = 2
    
    def handle_INIT(self):
        print "handle_INIT"
        #if self.users.has_key(name):
        #    print "Name taken, please choose another."
        #    self.state = 5
        #else:
        #    self.name = name
        #    self.users[name] = self
        #    self.usersWithCorrespondingChannels[name] = []
        #    self.state = 0
      

class brokerServerData(Protocol):
    def __init__(self,factory,queries):
        print "brokerServerData init."
        self.factory = factory
        self.queries = queries
        self.receivedDataBuffer = ""
        
    def test(self):
        print "test is OK"
    
    def connectionMade(self):
        self.factory.numDataProtocols = self.factory.numDataProtocols + 1
        print "There are currently",self.factory.numDataProtocols,"open data connections"
        #self.transport.write("Thanks,connectionMade from data")

    def connectionLost(self, reason):
        self.factory.numDataProtocols = self.factory.numDataProtocols - 1
        print "There are currently",self.factory.numDataProtocols,"open data connections"

    def dataReceived(self, data):
        print "Received data:",data
        
class brokerServerFactory(Factory):
    def __init__(self, typeCode):
        self.typeCode = typeCode
        self.numCommandProtocols = 0
        self.numDataProtocols = 0
        
        if self.typeCode == 0:
            print "brokerServerFactory init."
            self.users = {} # maps user names to instances
            self.commands = {0:"Subscribe", 1:"Unsubscribe", 2:"Status",3:"Init"} # commands
            self.channels = {0:"News", 1:"Sports", 2:"Finance", 3:"Cars"} # channels
            self.brokerServerMachineStates = {0:"GETNAME",1:"GETCOMMAND",2:"GETCHANNEL",3:"DELCHANNEL",4:"GETSTATUS",5:"BEGIN",6:"END"}
            self.usersWithCorrespondingChannels = {} # maps user names to their subscribe channels
            print "    ",len(self.commands),"commands have been set."
            print "    ",len(self.channels),"channels have been set."
            print "    ",len(self.brokerServerMachineStates),"machine states have been set."
            
        elif self.typeCode == 1:
            self.readQueriesFromDisk("/home/weijiang/workspace/polyIRToolkit/polyIRIndexer/1000query")

    def buildProtocol(self, addr):
        print "incoming address:",addr
        if self.typeCode == 0:
            return brokerServerCommand(self,self.users, self.commands, self.channels, self.brokerServerMachineStates, self.usersWithCorrespondingChannels)
            
        elif self.typeCode == 1:
            return brokerServerData(self,self.queries)
            
    def readQueriesFromDisk(self,fileName):
        inputFileHandler = open(fileName,"r")
        self.queries = {}
        for index,line in enumerate( inputFileHandler.readlines() ):
            self.queries[index] = line.strip()
        print "    ",len(self.queries),"queries have been loaded."

def gotProtocol(p):
    print p.getHost()
    commandPortANDdataPortReferenceList.append(p)
    
    '''
    if p.typeCode == 0:
        print "command:",p
        commandProtocolInstanceReference = p
    elif p.typeCode == 1:
        print "data:",p
        dataProtocolInstanceReference = p        
    else:
        print "typeCode NOT recognized."
    '''
#this broker factory can generate 2 kinds of products based on different type codes.
#typeCode: 0 for control port, 1 for data port
print "Program begins."
commandPortANDdataPortReferenceList = []

controlPort = 10876
controlPoint = TCP4ServerEndpoint(reactor,controlPort)
deferredForCommandPort = controlPoint.listen(brokerServerFactory(0))
deferredForCommandPort.addCallback(gotProtocol)

dataPort = 10877
dataPoint = TCP4ServerEndpoint(reactor,dataPort)
deferredForDataPort = dataPoint.listen(brokerServerFactory(1))
deferredForDataPort.addCallback(gotProtocol)

print len(commandPortANDdataPortReferenceList)

print "Waiting for connections..."
reactor.run()
print "Program end."
